package org.dbrd.model;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class PrecessingBugReport extends AbstractBugReport {

	protected static class IdHolder {

		private int id;

		public IdHolder(int id) {
			super();
			this.id = id;
		}

		public void setId(int newId) {
			if (newId < id) {
				this.id = newId;
			}
		}
	}

	protected IdHolder tempDuplicateIdHolder;

	protected PrecessingBugReport original;

	protected Set<PrecessingBugReport> duplicates;

	protected boolean visited;

	public PrecessingBugReport(int id, String originalSummary, String originalDescription, int duplicateId, final int priority,
			final String version, final String subComponent, final String issueType, String component) {
		super(id, originalSummary, null, originalDescription, null, duplicateId, priority, version, subComponent, issueType,
				component);
		this.duplicates = new HashSet<PrecessingBugReport>();
	}

	public void addDuplicate(PrecessingBugReport duplicate) {
		this.duplicates.add(duplicate);
	}

	public void setProcessedSummary(String processedSummary) {
		if (processedSummary == null || processedSummary.trim() == "") {
			throw new IllegalArgumentException("processedSummary cannot be empty." + this);
		}
		this.processedSummary = processedSummary;
	}

	public void setProcessedDescription(String processedDescription) {
		if (processedDescription == null || processedDescription.trim() == "") {
			throw new IllegalArgumentException("processedDescription cannot be empty." + this);
		}
		this.processedDescription = processedDescription;
	}

	public void locateDuplicate(Map<Integer, PrecessingBugReport> index) {
		if (this.isDuplicated()) {
			this.original = index.get(this.duplicateId);
			if (this.original == null) {
				// this report is duplicate to an old report which does not
				// exist.
				GhostPrecessingBugReport ghost = new GhostPrecessingBugReport(this.duplicateId);
				index.put(this.duplicateId, ghost);
				this.original = ghost;
				this.duplicateId = NON_DUPLICATE;
			}
			this.original.addDuplicate(this);
		} else {
			this.original = null;
		}
	}

	public void preAdjustDuplicateId() {
		if (this.visited) {
			return;
		}
		this.visited = true;
		if (this.original == null) {
			throw new RuntimeException("cannot invoke adjustDuplicateId() for a non-duplicate report.");
		}
		if (this.tempDuplicateIdHolder != null) {
			throw new RuntimeException();
		}
		this.tempDuplicateIdHolder = new IdHolder(this.id);
		this.original.passIdHolder(this.tempDuplicateIdHolder);
		// this.tempDuplicateIdHolder = this.original.adjustDuplicateId(new
		// IdHolder(this.id));
		for (PrecessingBugReport report : this.duplicates) {
			report.passIdHolder(this.tempDuplicateIdHolder);
		}
	}

	public void postAdjustDuplicateId() {
		if (this.tempDuplicateIdHolder != null) {
			this.duplicateId = this.tempDuplicateIdHolder.id;
		}
	}

	protected void passIdHolder(IdHolder idHolder) {
		if (this.visited) {
			if (idHolder != this.tempDuplicateIdHolder) {
				throw new RuntimeException();
			}
			return;
		} else {
			this.visited = true;
			if (this.tempDuplicateIdHolder != null) {
				throw new RuntimeException();
			}
			this.tempDuplicateIdHolder = idHolder;
			if (idHolder.id > this.id) {
				idHolder.id = this.id;
			}
			if (this.original != null)
				this.original.passIdHolder(idHolder);
			for (PrecessingBugReport r : this.duplicates) {
				r.passIdHolder(idHolder);
			}
		}
	}

	// protected IdHolder adjustDuplicateId(IdHolder idHolder) {
	// if (this.visited) {
	// if (this.tempDuplicateIdHolder == null) {
	// throw new RuntimeException();
	// }
	// return this.tempDuplicateIdHolder;
	// }
	// this.visited = true;
	// this.tempDuplicateIdHolder = idHolder;
	// if (idHolder.id > this.id) {
	// idHolder.setId(this.id);
	// }
	// return idHolder;
	// }

}
